package parser_antlr4.aspect;

import parser_antlr4.Parser;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;

public class ParserInvocationHandler implements InvocationHandler {
  private final Parser target;
  private final List<ParserAspect> aspects;

  public ParserInvocationHandler(Parser target, ParserAspectContainer parserAspectContainer) {
    this.target = target;
    boolean findSQLCleanParser = false;
    boolean findSQLCheckBlank = false;
    for (ParserAspect aspect : parserAspectContainer.getAspects()) {
      if (aspect instanceof ParserAspectSQLClean) {
        findSQLCleanParser = true;
      }

      if (aspect instanceof ParserAspectSQLNotBlank) {
        findSQLCheckBlank = true;
      }
    }

    if (!findSQLCheckBlank) {
      parserAspectContainer.addParserAspect(new ParserAspectSQLNotBlank());
    }

    if (!findSQLCleanParser) {
      parserAspectContainer.addParserAspect(new ParserAspectSQLClean());
    }

    this.aspects = parserAspectContainer.getAspects();
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    for (ParserAspect parserAspect : aspects) {
      if (parserAspect.enabled()) {
        parserAspect.beforeParse(method, args);
      }
    }

    Object result;
    try {
      result = method.invoke(target, args);
      aspects.forEach(aspect -> {
        if (aspect.enabled()) {
          aspect.afterParse(method, args, result);
        }
      });

    } catch (Exception e) {
      aspects.forEach(aspect -> {
        if (aspect.enabled()) {
          aspect.onError(method, args, e);
        }
      });
      throw e;
    }
    return result;
  }
}